#! /bin/bash

## hunalf (AT) gmail.com, 2008-09-22
## GPL v2
## not completed yet

get_safe_inface()
{
    echo eth1 eth{3..10}
    echo "tun+"
    echo lo
    echo "tap+"
}

get_safe_proto()
{
    echo icmp
}

get_safe_src()
{
    echo 127.0.0.1
}

is_a_safe_iface()
{
    local iface=$1
    local safe_i

    for safe_i in $( get_safe_inface ); do
        if [[ $iface == $safe_i ]]; then
            return 0
        fi
    done

    return 1
}

is_a_safe_proto()
{
    local proto=$1
    local safe_p

    for safe_p in $( get_safe_proto ); do
        if [[ $proto == $safe_p ]]; then
            return 0
        fi
    done

    return 1
}

is_a_safe_src()
{
    local src=$1
    local safe_s

    case $src in
        127.*)
            return 0
            ;;
        192.168.*)
            return 0
            ;;
        172.*)
            return 0
            ;;
        10.*)
            return 0
            ;;
    esac

    for safe_s in $( get_safe_src ); do
        if [[ $src == $safe_s ]]; then
            return 0
        fi
    done

    return 1
}

is_a_related_rule()
{
    echo $@ | grep -wq RELATED
}

is_a_established_rule()
{
    echo $@ | grep -wq ESTABLISHED
}

is_drop_all()
{
    local target=$1
    local src=$2
    local destination=$3

    if [[ $target == "DROP" ]] && [[ $src == "0.0.0.0/0" ]] && [[ $destination == "0.0.0.0/0" ]]; then
        return 0
    else
        return 1
    fi

}

is_a_drop()
{
    local target=$1
    case $target in
        DROP|REJECT)
            return 0
            ;;
        *)
            return 1
            ;;
    esac
}

guess_policy()
{
    :
}

check_ipt_rules()
{
    local pkts bytes target prot opt inn out src destination

    iptables -nvL $* | while read pkts bytes target prot opt inn out src destination rest; do

        ## ignore blank line
        if [[ -z $pkts ]]; then
            continue
        fi

        ## ignore chain name line
        if [[ $pkts == "Chain" ]]; then
            continue
        fi

        ## ignore info not about real rules
        if [[ $pkts == "pkts" ]]; then
            continue
        fi

        ## rule to drop everything, break here
        if is_drop_all $target $src $destination; then
            break
        fi

        ## drop | reject
        if is_a_drop $target; then
            continue
        fi

        ## ignore safe interface
        if is_a_safe_iface $inn; then
            continue
        fi

        ## ignore safe protocals
        if is_a_safe_proto $prot; then
            continue
        fi

        ## ignore safe src
        if is_a_safe_src $src; then
            continue
        fi

        ## ignore related stat
        if is_a_related_rule "$rest"; then
            continue
        fi

        ## ignore established stat
        if is_a_established_rule "$rest"; then
            continue
        fi

        ## accept
        if [[ $target == "ACCEPT" ]]; then
            #echo "$pkts $bytes $target $prot $opt $inn $out $src $destination $rest"
            ## may have bugs here
            local sport=$( echo $rest | perl -ne 'print $1 if m{spt:(\d+)}' )
            local dport=$( echo $rest | perl -ne 'print $1 if m{dpt:(\d+)}' )
            echo -e "proto:$prot\tfrom:${src%/0}:${sport:-any}\tto:${destination%/0}:${dport:-any}"

        ## sub-chain, shoud check this chain recursively
        else
            #echo "CHAIN: $target"
            check_ipt_rules $target
        fi

        ## check if we has a drop all here
    done
}


## ------------------------------------------------------------- ##

check_ipt_rules -t filter
